package yu.ac.bg.etf.kdp.radnastanica;

import java.util.*;
import java.io.*;
import java.net.*;
import rs.ac.bg.etf.kdp.math.*;

import yu.ac.bg.etf.kdp.klase.*;

public class Workstation extends Thread {

	private ServerSocket workstationsListener;
	private ServerSocket serverListener;

	protected String localHost;

	protected int workstationsListenerPort;
	private int serverListenerPort;

	protected String serverHost;
	protected int serverPort;

	protected Equations equations;
	protected Connector connector;
	private int jobCapacity;
	private boolean working;
	
	private LinkedList handlerList;

	public Workstation() {
		this("localhost", 4001, 1);
	}

	public Workstation(String host, int port, int jobCapacity) {
		try {
			working = true;
			serverHost = host;
			serverPort = port;
			if (jobCapacity > 0)
				this.jobCapacity = jobCapacity;
			else
				this.jobCapacity = 0;
			handlerList = new LinkedList();
			// otvaramo serverski socket koji ce sluziti za
			// komunikaciju izmedju radnih stanica
			workstationsListener = new ServerSocket(0);
			workstationsListenerPort = workstationsListener.getLocalPort();
			InetAddress localMachine = InetAddress.getLocalHost();
			localHost = localMachine.getHostName();
			// otvaramo serverski port koji ce sluziti za
			// prihvatanje zahteva pristiglih od servera
			serverListener = new ServerSocket(4005);
			serverListenerPort = serverListener.getLocalPort();
			// inicijalizujemo klase potrebne za
			// paralelno izracunavanje
			equations = Creator.createEquations();
			connector = Creator.createConnector();
			// prijavljujemo nasu radnu stanicu serveru
			registerOnServer();
			System.out.println("Workstation registered on server..");

		} catch (IOException e1) {
			System.out.println("Connection broken..");
			System.exit(1);
		}

	}
	
	public void stopWorkstation () {
		for (int i = 0;i < handlerList.size();i++) {
			try {
				((WorkstationThread)handlerList.get(i)).join();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				System.out.println("Workstation interrupted while waiting on handler to finish..");
			}
		}
		try {
			working = false;
			serverListener.close();
			workstationsListener.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			System.out.println("Connection broken1..");
			System.exit(1);
		}
	}

	public void registerOnServer() {
		try {
			// kacimo se na server
			Socket sock = new Socket(serverHost, serverPort);
			// inicijalizujemo tokove podataka
			ObjectOutputStream outo = new ObjectOutputStream(sock.getOutputStream());
			outo.flush();
			ObjectInputStream ino = new ObjectInputStream(sock.getInputStream());
			// saljemo podatke o sebi po protokolu
			outo.writeObject(new MsgTxt("wstaRequest"));
			outo.flush();
			outo.writeObject(new MsgTxt("register"));
			outo.flush();
			outo.writeObject(new Node(localHost, workstationsListenerPort,
					localHost, serverListenerPort, jobCapacity));
			outo.flush();
			Msg msg = (Msg) ino.readObject();
			String str = (String) msg.getBody();
			if (!str.equals("ack")) {
				System.out.println("Bad protocol message..");
				System.exit(1);
			}
			// zatvaramo komunikaciju
			outo.close();
			ino.close();
			sock.close();
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			System.out.println("Unknown server host..");
			working = false;
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			System.out.println("Connection broken..");
			working = false;
		} catch (ClassNotFoundException e2) {
			System.out.println("Class not found..");
			working = false;
		}
	}

	public void run() {
		try {
			while (working) {
				Socket sock = serverListener.accept();
				WorkstationThread handler = new WorkstationThread(this, sock);
				handlerList.add(handler);
				handler.start();
			}
		} catch (SocketException e1) {
			System.out.println("Server listener closed..");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			System.out.println("Connection broken2..");
			System.exit(1);
		}
	}

	public NodeList getOtherWorkstations() {
		NodeList nodeList = null;
		try {
			System.out.println("Getting other worksations..");
			Socket sock = new Socket(serverHost, serverPort);
			ObjectOutputStream outo = new ObjectOutputStream(sock
					.getOutputStream());
			outo.flush();
			ObjectInputStream ino = new ObjectInputStream(sock.getInputStream());
			outo.writeObject(new MsgTxt("wstaRequest"));
			outo.flush();
			outo.writeObject(new MsgTxt("getNods"));
			outo.flush();
			nodeList = (NodeList) ino.readObject();
			outo.close();
			ino.close();
			sock.close();
			System.out.println("Got other workstations..");
		} catch (UnknownHostException e1) {
			// TODO Auto-generated catch block
			System.out.println("Unknown server host..");
			System.exit(1);
		} catch (IOException e2) {
			// TODO Auto-generated catch block
			System.out.println("Connection broken..");
			System.exit(1);
		} catch (ClassNotFoundException e3) {
			// TODO Auto-generated catch block
			System.out.println("Class not found..");
			System.exit(1);
		}
		return nodeList;
	}

	public boolean isWorking () {
		return working;
	}
	
	public static void main (String[] args) {
		Workstation wsta = new Workstation("localhost",4002,1);
		wsta.start();
		System.out.println("Workstation started..");
		NodeList nodeList = wsta.getOtherWorkstations();
		for (int i = 0;i < nodeList.size();i++) {
			System.out.println(((Node)nodeList.get(i)).getHostForServer());
		}
	}
	
}
